﻿namespace SerializationPerformance
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Windows;
    using Microsoft.Phone.Controls;
    using Serialization;
    using WP7Contrib.Collections;
    using WP7Contrib.Common;

    public partial class MainPage : PhoneApplicationPage
    {
        private static DataContractSerializer dataContractSerializer;

        public MainPage()
        {
            InitializeComponent();
        }
        
        private void LayoutRootLoaded(object sender, RoutedEventArgs e)
        {
            dataContractSerializer = new DataContractSerializer(typeof(ObservableCollection<Product>));

            SilverlightSerializer.RegisterSerializationAssembly(typeof(MainPage).Assembly);
            SilverlightSerializer.RegisterSerializationAssembly(typeof(BaseModel).Assembly);
        }

        private void RunTestClick(object sender, RoutedEventArgs e)
        {
            var data = CreateData();

            var dataContractStopWatch = new Stopwatch();
            var silverlightSerializerStopWatch = new Stopwatch();

            dataContractStopWatch.Start();
            var dataContractResult = DataContractSerialization(data);
            dataContractStopWatch.Stop();

            silverlightSerializerStopWatch.Start();
            var silverlightSerializerResult = SilverlightSerialization(data);
            silverlightSerializerStopWatch.Stop();

            Debug.WriteLine("*************************************");

            Debug.WriteLine("Data Contract Serializer: {0} ticks", dataContractStopWatch.ElapsedTicks.ToString("N0"));
            Debug.WriteLine("Data Contract Serializer: {0} ms", dataContractStopWatch.ElapsedMilliseconds.ToString("N0"));
            Debug.WriteLine("Data Contract Serializer: {0} bytes", dataContractResult.Length.ToString("N0"));

            Debug.WriteLine("Silverlight Serializer:   {0} ticks", silverlightSerializerStopWatch.ElapsedTicks.ToString("N0"));
            Debug.WriteLine("Silverlight Serializer:   {0} ms", silverlightSerializerStopWatch.ElapsedMilliseconds.ToString("N0"));
            Debug.WriteLine("Silverlight Serializer:   {0} bytes", silverlightSerializerResult.Length.ToString("N0"));

            Debug.WriteLine("*************************************");
        }

        private static byte[] DataContractSerialization(ObservableCollection<Product> products)
        {
            byte[] dataContractResult;

            using (var dataContractMemoryStream = new MemoryStream())
            {
                dataContractSerializer.WriteObject(dataContractMemoryStream, products);

                dataContractResult = new byte[dataContractMemoryStream.Length];
                dataContractMemoryStream.Read(dataContractResult, 0, dataContractResult.Length);
            }

            return dataContractResult;
        }

        private static byte[] SilverlightSerialization(ObservableCollection<Product> products)
        {
            return SilverlightSerializer.Serialize(products);
        }
        
        private static ObservableCollection<Product> CreateData()
        {
            var products = new ObservableCollection<Product>();
            for (var i = 0; i < 1000; i++)
            {
                var p = new Product
                {
                    Name = RandomTextGenerator.CapitalisedText(3, 7),
                    Description = RandomTextGenerator.Description(10, 30),
                };

                products.Add(p);
            }

            return products;
        }
    }

    [Serializer(typeof(ObservableCollection<Product>))]
    public sealed class ProductCollectionSerializer : ISerializeObject
    {
        public object[] Serialize(object target)
        {
            var tmp = (ObservableCollection<Product>)target;
            return new object[] { tmp.ToList() };
        }

        public object Deserialize(object[] data)
        {
            var tmp = new ObservableCollection<Product>();

            var items = (List<Product>)data[0];
            items.ForEach(tmp.Add);

            return tmp;
        }
    }
}